# -*- coding: utf-8 -*-
__author__ = 'gerry'


import numpy as np


import matplotlib.pyplot as plt
a = np.array([1, 2, 3, 4])  # 以列表组成的一维数组
b = np.array((5, 6, 7, 8))  # 以字典组成的一维数组
c = np.array([[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 4, 5]])  # 二维数组
print '=================================================================='
# 1、矩阵的形状
print a.shape, b.shape, c.shape
c.shape = 4, 3  # 并不是对数组进行转置，而是改变每个轴的大小，数组元素在内存中的位置并没有改变
print c.shape
print c

c.shape = 2, -1  # 当设置某个轴的元素个数为-1时，将自动计算此轴的长度，由于这个数组c有12个元素，因此下面的程序将c的shape属性改为（2,6）
print c.shape
print c

print '=================================================================='
d = a.reshape((2, 2))  # 创建指定形状的新数组，而原数组的形状保持不变
print d
print a
# 数组a和d其实共享数据存储空间，因此修改其中任意一个数组的元素都会同时修改另一个数组的内容
a[1] = 1
print d
print a

print '=================================================================='
# 2、元素的类型
# 数组的元素类型可以通过dtype属性获得
print c.dtype
# 可以通过dtype参数在创建数组的时候指定元素类型，注意float类型64位双精度浮点型，而complex是128位的双精度复数类型
ai32 = np.array([1, 2, 3, 4], dtype=np.int32)
af = np.array([1, 2, 3, 4], dtype=float)
ac = np.array([1, 2, 3, 4], dtype=complex)
print ai32.dtype, af.dtype, ac.dtype
# 数组类型的转换
t1 = np.array([1, 2, 3, 4], dtype=np.float)
t2 = np.array([1, 2, 3, 4], dtype=np.complex)

t3 = t1.astype(np.int32)
t4 = t2.astype(np.complex64)

print '=================================================================='
# 3、自动生成数组
# 前面的例子都是首先创建一个Python的序列对象，然后通过arra()将其转换为数组，这样做显然效率不高
# arange()类似于内置函数range(),通过指定开始值、终值和步长来创建表示等差数列的一维数组
# 注意所得到的结果中不包含终值。
arr1 = np.arange(0, 1, 0.1)
print arr1

# linspace()通过指定开始值、终值和元素个数来创建表示等差数列的一维数组，可以通过endpoint参数指定是否包含终值，默认为TRUE，即包含终值
linsp1 = np.linspace(0, 1, 10)  # 步长为1/9
linsp2 = np.linspace(0, 1, 10, endpoint=False)  # 步长为1/10
print linsp1
print linsp2
# logspace()和linspace类似，不过它所创建的数组是等比数列。
logsp1 = np.logspace(0, 2, 5)
logsp2 = np.logspace(0, 1, 12, base=2, endpoint=False)  # base指定基数，endpoint是否包含终值
print logsp1
print logsp2


print '=================================================================='
# zeros()、ones()、empyt()可以创建指定形状和类型的数组。其中empty()只分配数组所使用的内存，不对数组元素进行初始化操作，因此它的运行速度是最快的
empty1 = np.empty((2,3),np.int)
print empty1
#zeros()将数组元素初始化为0，ones()将数组元素初始化为1，
zeros1 = np.zeros(4,np.int)
print zeros1

#full()将数组元素初始化为指定的值
full1 = np.full(4,np.pi)
print full1

#np.zeros_like(a),np.ones_like(a),np.empty_like(a),np.full_like()等函数创建与参数数组形状和类型相同的数组，因此zeros_like(a)和zeros(a.shape,a.dtype)的效果相同


print '=================================================================='
#4、存取元素
a1 = np.arange(10)
print a1
print a1[5] #用整数作为下标可以获取数组中的某个元素
print a1[3:5] #用切片作为下标获取数组的一部分，包括a[3]但不包括a[5]
print a1[:5] #切片中省略开始下标，表示从a[0]开始
print a1[:-1]#下标可以使用负数，表示数组从后向前数

print a1[1:-1:2]#切片中的第三个参数表示步长，2表示隔一个元素取一个元素
print a1[::-1]#省略切片的开始下标和结束下标，步长为-1，整个数组头尾颠倒
print a1[5:1:-2]#步长为负数时，开始下标必须大于结束下标
a1[2:4] = 100,101 #下标可以用来修改元素的值
print a1
#注意：和列表不同的是，通过切片获取的新的数组时原始数组的一个视图，它与原始数组共享同一块数据存储空间。



print '=================================================================='

#除了使用切片下标存取元素之外，numpy还提供了整数列表、整数数组和布尔数组等几种高级下标存取方法
#当使用整数列表对数组元素进行存取时，将使用列表中的每个元素作为下标，是用列表作为下标得到的数组不和原始数组共享数据
x = np.arange(10,1,-1)
print x

x1 = x[[3,3,1,8]] #获取x中下标为3,3,1,8的四个元素，组成一个新的数组
x2 = x[[3,3,-3,8]] #下标可以为负数，-3表示取倒数第3个元素
print x1
print x2

x2[2]=100#由于x2和x不共享内存，因此x的值不变
print x2
print x
x[[3,5,1]] = -1,-2,-3 #整数序列下标也可以修改元素的值
print x


print '=================================================================='
#多维数组

adrr = np.arange(0,60,10).reshape(-1,1)+np.arange(0,6)
print adrr
print adrr[0,3:5]
print adrr[4:,4:]
print adrr[:,2]
print adrr[2::2,::2]

# 如果下标元组中只包含整数和切片,那么得到的数组和原始数组共享数据，它是原始数组的视图
bdrr = adrr[0,3:5]
bdrr[0] = -bdrr[0]
print adrr[0,3:5]

print '=================================================================='

#创建数组下标
#使用Python的内置函数slice()创建下标比较麻烦，因此Numpy提供了一个s_对象来帮助创建数组下标，请注意s_实际上是IndexExperssion类的一个对象
np.s_[::2,2:]

#在多维数组的下标元组中，也可以使用整数元组或者列表、整数数组和布尔数组，当下标中使用这些对象时，所获得的数据是原始数据的副本，因此修改结果数组不会改变原始数组

print adrr[(0,1,2,3),(1,2,3,4)] #整数元组
print adrr[3:,[0,2,5]]  # 列表数组
mask = np.array([1,0,1,0,0,1],dtype=np.bool) #布尔数组
mask1 = [True,False,True,False,False,True]
print adrr[mask,2]





print '=================================================================='
#6、结构数组
#在C语言中我们可以通过struct关键字定义结构类型，结构中的字段占据连续的内存空间。类型相同的两个结构所占用的内存大小相同。

persontype = np.dtype({
    'names':['name','age','weight'],
    'formats':['S30','i','f']},align=True)# align=True表示内存对齐
#创建一个dtype对象persontype,它的参数是一个描述结构类型的各个字段的字典。字典有两个键:'names'和'formats'。
#每个键对应的值都是一个列表。
#'names'定义结构中每个字段的名称
#'formats'则定义每个字段的类型
#*'S30':长度为30个字节的字符串类型，由于结构中的每个元素的大小必须固定，因此需要指定字符串的长度
#*'i':32位整数类型，相当于np.int32
#*'f':32位的单精度浮点数类型，相当于np.float32

struct1 = np.array([("Zhang",32,75.5),("Wang",24,65.2)],dtype=persontype)
print struct1.dtype
#'names':['name','age','weight'], 'formats':['S30','<i4','<f4'], 'offsets':[0,32,36], 'itemsize':40, 'aligned':True}
#其中形如"(字段名，类型描述)"的元组描述了结构中的每个字段。类型字符串前面的'|','<','>'等字符表示字段值的字节顺序
#'|':忽视字节顺序
#'<':低位字节在前，即小端模式
#'>':高位字节在前，即大端模式
print struct1[0]
print struct1[0]['name']
#struct1[0]是一个结构元素，它和数组a共享内存数据，因此可以通过修改它的字段来改变原始数组中对应元素的字段
c = struct1[1]
c['name'] = 'Li'
print struct1[1]["name"]

print '=================================================================='

















































